<script setup lang="ts">
import type { CropperFile, CropperOption } from './index'
import { Minus, Plus, Upload } from '@element-plus/icons-vue'
import { VueCropper } from 'vue-cropper'

const props = withDefaults(defineProps<CropperOption>(), {
  img: '',
  /* 容器宽度 */
  boxWidth: 500,
  /* 容器高度 */
  boxHeight: 380,
  /* 裁剪生成图片的质量 */
  outputSize: 1,
  /* 默认生成截图框宽度 */
  autoCropWidth: '200',
  /* 默认生成截图框高度 */
  autoCropHeight: '200',
  /* 裁剪生成图片的格式 */
  outputType: 'jpeg',
  /* 裁剪框的大小信息 */
  info: true,
  /* 图片是否允许滚轮缩放 */
  canScale: true,
  /* 是否默认生成截图框 */
  autoCrop: true,
  /* 是否开启截图框宽高固定比例 */
  fixed: false,
  /* 是否输出原图比例的截图 */
  full: false,
  /* 固定截图框大小 */
  fixedBox: true,
  /* 上传图片是否可以移动 */
  canMove: true,
  /* 截图框能否拖动 */
  canMoveBox: true,
  /* 上传图片按照原始比例渲染 */
  original: false,
  /* 截图框是否被限制在图片里面 */
  centerBox: false,
  /* 是否按照设备的dpr 输出等比例图片 */
  high: true,
  /* true 为展示真实输出图片宽高 false 展示看到的截图框宽高 */
  infoTrue: false,
  /* 限制图片最大宽度和高度 */
  maxImgSize: 2000,
  /* 图片根据截图框输出比例倍数 */
  enlarge: 1,
  /* 图片默认渲染方式 */
  mode: 'contain',
  /* 裁剪框限制最小区域 */
  limitMinSize: 10,
})

const emit = defineEmits<{
  /**
   * 截图框实时输出
   * @param width 截图框宽度
   * @param height 截图框高度
   * @param previewStyle 预览样式
   * @param img 图片地址
   */
  (e: 'realTime', args: {
    width: number
    height: number
    previewStyle: string
    img: string
  }): void
}>()

// 裁剪框样式
const newOptions = $ref<CropperOption>({ ...props })
const cropper = $ref(VueCropper)
const fileInput = $ref<HTMLInputElement>()
// 文件数据
const fileData = reactive<CropperFile>({
  fileName: newOptions.img ?? '',
})

/**
 * 截图
 * @returns Promise<CropperFile>
 */
function cropperSubmit(): Promise<CropperFile> {
  return new Promise((resolve, reject) => {
    cropper.getCropBlob((data: any) => {
      fileData.file = data

      resolve(fileData)
    }, (error: Error) => {
      reject(error)
    })
  })
}

/**
 * 实时预览
 */
function realTime(data: { w: number, h: number, img: string }) {
  emit('realTime', {
    width: data.w,
    height: data.h,
    previewStyle: data.img,
    img: newOptions.img ?? '',
  })
}

// 上传图片
function upload() {
  fileInput?.click()
}
// 放大
function amplify() {
  cropper.changeScale(2)
}
// 缩小
function reduction() {
  cropper.changeScale(-2)
}
// 向左转
function leftTurn() {
  cropper.rotateRight()
}
// 向右转
function rightTurn() {
  cropper.rotateLeft()
}
// 选择图片
function handleFileChange(event: Event) {
  const target = event.target as HTMLInputElement
  const files = target.files
  if (files && files.length > 0) {
    // 限制只能上传图片
    const file = files[0]
    if (!file.type.match('image.*')) {
      Message({
        message: '请上传图片文件',
        type: 'error',
      })
      return
    }
    fileData.fileName = file.name
    const reader = new FileReader()
    reader.onload = (e) => {
      const arrayBuffer = e.target!.result
      const blob = new Blob([arrayBuffer as BlobPart], { type: file.type })
      newOptions.img = URL.createObjectURL(blob)
    }
    reader.readAsArrayBuffer(file)
  }
}

defineExpose({ cropperSubmit })
</script>

<template>
  <div class="cropper">
    <div
      :style="{
        width: `${newOptions.boxWidth}px`,
      }"
    >
      <div
        :style="{
          height: `${newOptions.boxHeight}px`,
        }"
        class="cut"
      >
        <VueCropper ref="cropper" v-bind="newOptions" @real-time="realTime" />
      </div>
      <!--  隐藏上传图片框  -->
      <input
        ref="fileInput"
        accept="image/*"
        style="display: none"
        type="file"
        @change="handleFileChange"
      >
      <div class="cropper-handle">
        <el-tooltip
          content="上传图片"
          placement="top"
        >
          <el-button @click="upload">
            <template #icon>
              <el-icon><Upload /></el-icon>
            </template>
          </el-button>
        </el-tooltip>
        <el-tooltip
          content="放大"
          placement="top"
        >
          <el-button @click="amplify">
            <template #icon>
              <el-icon><Plus /></el-icon>
            </template>
          </el-button>
        </el-tooltip>
        <el-tooltip
          content="缩小"
          placement="top"
        >
          <el-button @click="reduction">
            <template #icon>
              <el-icon><Minus /></el-icon>
            </template>
          </el-button>
        </el-tooltip>
        <el-tooltip
          content="左转"
          placement="top"
        >
          <el-button @click="leftTurn">
            <template #icon>
              <sy-icon icon="material-symbols-light:rotate-left" />
            </template>
          </el-button>
        </el-tooltip>
        <el-tooltip
          content="右转"
          placement="top"
        >
          <el-button @click="rightTurn">
            <template #icon>
              <sy-icon icon="material-symbols-light:rotate-right" />
            </template>
          </el-button>
        </el-tooltip>
      </div>
    </div>
  </div>
</template>

<style scoped>
.cropper {
  .cut {
    overflow: hidden;
    border-radius: var(--el-border-radius-base);
  }
  .cropper-handle {
    margin-top: 10px;
    .sy-button {
      padding: 5px;
      height: auto;
    }
  }
}
</style>
